home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / videbjct / cvd1000d.c next >
Encoding:
Text File  |  1993-06-15  |  56.3 KB  |  1,667 lines

  1. /*
  2.  * Copyright (c) 1992 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23.  
  24. /* $Header: /Source/Media/collab/VideoObject/RCS/CVD1000Driver.c,v 1.21 92/10/02 13:58:15 drapeau Exp $ */
  25. /* $Log:    CVD1000Driver.c,v $
  26.  * Revision 1.21  92/10/02  13:58:15  drapeau
  27.  * Removed code in PlayFromTo method that takes pre-roll time into account; that
  28.  * is, the Vdeck takes about two seconds before audio can be heard with video,
  29.  * but this code no longer tries to correct for that.  A new VideoObject should
  30.  * really be designed to take care of this type of problem.
  31.  * 
  32.  * Revision 1.20  92/09/28  12:38:23  drapeau
  33.  * Fixed an error in the PlayFromTo() function.  The wrong variable was used
  34.  * to hold the result of a QueryFrame() call.
  35.  * 
  36.  * Revision 1.19  92/09/24  16:24:00  drapeau
  37.  * Primary change was in the semantics of the PlayFromTo method.  The semantics
  38.  * have been changed: in the new case, when fromAddress == toAddress, a
  39.  * non-blocking search has been requested; when fromAddress != 0 and
  40.  * toAddress == 0, a blocking search has been requested.  This is a different
  41.  * interpretation than before; it was determined that it was more important to
  42.  * give the application programmer a choice between blocking and non-blocking
  43.  * searches than it was to have the programmer decide to search to an address
  44.  * and continue playing from there (since this latter interpretation can be
  45.  * emulated by a call to DevPlayFromTo(startAddress, 0) and DevPlay()).
  46.  * 
  47.  * Also, minor cosmetic changes were made to the code for improved readability.
  48.  * 
  49.  * Revision 1.18  92/09/04  16:42:12  drapeau
  50.  * Modified CVD1000PlayFromTo(), case b (startAddress == 0,
  51.  * endAddress > 0).  This means to play from the current
  52.  * position until some end address is reached, intended to be used in editing
  53.  * situations where this is the playback deck.  The driver now takes into
  54.  * account that the deck doesn't "warm up" for a couple of seconds.  So,
  55.  * the driver now begins playback in this case two seconds before the actual
  56.  * starting point of the edit (if the edit is less than 2 seconds from the
  57.  * beginning of the tape, the edit will begin at time zero; this means that
  58.  * authors should never put usable video material on, say, the first 10
  59.  * seconds of a videotape).
  60.  * 
  61.  * Revision 1.17  92/09/04  14:25:14  drapeau
  62.  * Made a number of changes to improve the overall quality of the driver:
  63.  * * Added prefix "CVD1000" to all new functions, for better code
  64.  *   encapsulation and programming practice.  For example, the function
  65.  *   InputPending() is now CVD1000InputPending().
  66.  * * Improved clarity of diagnostic messages.
  67.  * * Major modifications to the RecordFromTo() method, to take into
  68.  *   account timing conditions between the record and playback decks.
  69.  *   For example, it is not necessary to block during the search phase
  70.  *   (searching for the start of the playback and start of the record
  71.  *   frame), but the function should block before going into insert
  72.  *   edit mode (the function makes sure that any searching is completed
  73.  *   before going into insert edit mode).  Also, the function should block
  74.  *   until the complete segment has been recorded.  This is one of the few
  75.  *   times that the driver blocks.
  76.  *   Also, fixed errors in the way commands were sent to the Vdeck to enable
  77.  *   segment recording.  Before, a command was sent to begin recording only
  78.  *   after a delay equal to the time it would take the playback deck to play
  79.  *   the segment.  The effect was that the playback deck would play the
  80.  *   segment, then the record deck would engage, thus recording nothing but
  81.  *   still frames (or empty video).  Now, the command sent is to begin
  82.  *   recording immediately and to *end* after a delay time equal to the
  83.  *   length of the segment.
  84.  * * Added functions SearchIsInProgress() and EditIsInProgress(), to check
  85.  *   the status of the Vdeck.  Used by the RecordFromTo() functions.
  86.  * * Note: this driver is still somewhat inaccurate for insert editing; as
  87.  *   written, the driver tends to make the deck record a few seconds after
  88.  *   the end of a segment.  Perhaps another approach to stopping the Edit
  89.  *   Record would work better.
  90.  * 
  91.  * Revision 1.16  92/09/02  17:11:17  drapeau
  92.  * Added new function, CVD1000Cancel(), to send cancellation messages for
  93.  * commands that are to be aborted.  Currently not used, although the function
  94.  * was used in intermediate development and deemed necessary to keep for
  95.  * possible future use.
  96.  * Also, added a few more diagnostic messages for easier debugging.
  97.  * Also, minor cosmetic changes to conform to style guidelines and to
  98.  * simplify the task of reading the code.
  99.  * 
  100.  * Revision 1.15  92/09/01  17:13:34  drapeau
  101.  * Made a number of changes:
  102.  * * Cosmetic changes to make code more readable.
  103.  * * Added two new methods, CVD1000Record() and CVD1000RecordFromTo(), in
  104.  *   accordance with new additions to the VideoObject.
  105.  * * Modified CVD1000ReadAsynch() to make it less dependent on a
  106.  *   particular programming toolkit.
  107.  * * Modified CVD1000PlayFromTo() to make more clear what each possible
  108.  *   case is.  The logic was not obvious before, and did not directly
  109.  *   reflect the documentation for the VideoObject.
  110.  * * Modified CVD1000PlayAtSpeedDir(); removed test that last speed must
  111.  *   be different from speed currently being requested.  This was necessary
  112.  *   in order to make the PlayFromTo() method work, since it is independent
  113.  *   of whatever speed was last requested.  The logic for determining whether
  114.  *   a PlayAtSpeedDir() really should be sent is now the responsibility of the
  115.  *   application programmer; the tools to determine whether the call should be
  116.  *   made are already in the VideoObject library (e.g., DevCalcSpeed()).
  117.  * 
  118.  * Revision 1.14  92/08/25  16:28:52  drapeau
  119.  * Major modifications to this driver:
  120.  * * Re-implemented the code that interprets the VISCA protocol, especially
  121.  *   that code which reads replies from the Vdeck.  In the process, greatly
  122.  *   simplified the protocol interpreter.
  123.  * * Removed the ParseResponse() function, since it is replaced by simpler
  124.  *   routines for reading VISCA replies.
  125.  * * Removed the CVD1000GetResponse() function, since it too is obsolete.
  126.  * * Greatly simplified the CVD1000ReadAsynch() function, since it can now call
  127.  *   the utility function "CVD1000ReadReply()" to consume input from the Vdeck.
  128.  * * Major changes to the CVD1000SendCode() function, to reflect simplifications
  129.  *   in the protocol interpreter.  Removed an unneccesary function parameter;
  130.  *   the calling functions now fill in the submode data themselves, instead
  131.  *   of having SendCode() try to do it.  SendCode() also consumes replies from
  132.  *   the Vdeck more intelligently and simply.
  133.  * * Modified functions that call CVD1000SendCode() to take the new argument
  134.  *   scheme and command formatting into account.  Also, removed calls to the
  135.  *   obsolete function CVD1000GetResponse(), since CVD1000SendCode() now
  136.  *   performs that function.
  137.  * * Added two functions, CVD1000ReadReply() and CVD1000ReadInquiryReply(), to
  138.  *   read replies of all types from the Vdeck.
  139.  * 
  140.  * Revision 1.13  92/08/05  16:17:30  drapeau
  141.  * Changed octal representations of opcodes to hex, to make reading
  142.  * easier for humans.
  143.  * 
  144.  * Revision 1.12  92/07/30  15:30:52  drapeau
  145.  * Several changes:
  146.  * 
  147.  * * Re-formatted all function declarations to conform to ANSI function
  148.  *   prototype standards.
  149.  * * Replaced hard-coded references to 30 frame-per-second frame rates with
  150.  *   new definition "FrameRate".  All math is based on this definition now,
  151.  *   allowing the driver to be used in places where the frame rate is not
  152.  *   30 fps.
  153.  * * Improved diagnostic messages.  Diagnostics now report the serial port
  154.  *   being used for the command when possible.
  155.  * 
  156.  * Revision 1.11  92/06/17  01:00:25  drapeau
  157.  * Changed termio usage, used more portable "termio" structure and
  158.  * associated calls instead of "termios".
  159.  * 
  160.  * Revision 1.10  92/06/17  00:21:02  drapeau
  161.  * Updated copyright notice.
  162.  * 
  163.  * Revision 1.0  92/06/17  00:16:22  drapeau
  164.  * Initial revision
  165.  *  */
  166.  
  167. #include "CVD1000Driver.h"
  168.  
  169. /* Assumption : only 1 device is being controlled. 
  170.    no daisy-chain, so address assignment is not done. 
  171.    all commands use destination address 1. */
  172. /* Time is encoded in BCD */
  173.  
  174. static char cvdrcsid[] = "$Header: /Source/Media/collab/VideoObject/RCS/CVD1000Driver.c,v 1.21 92/10/02 13:58:15 drapeau Exp $";
  175. OutCommand*        listHead = NULL;                /* Holds list of socket numbers of ACKs that have not
  176.                                        been matched with COMPLETIONS, essentially resulting
  177.                                        from PlayFromTo calls (can have multiple such calls 
  178.                                        in succession)  */
  179. OutCommand*        listTail = NULL;
  180. int            addMode;                    /* Addressing mode : PlayerFrameMode (normal), 
  181.                                                          PlayerChapterMode (chapter/index) */
  182. char            reply[50];                    /* Place into which replies are read from file descriptor */
  183. char            command[20];
  184. static char        diagMsg[128];
  185.  
  186. int            videoDisplay;                    /* Video Display state info (can't get this from CVD1000) */
  187. static VideoObject*    tempObjectPtr;                    /* Used for the asynchronous read function */
  188.  
  189.  
  190. /* Function to add new element to list of unmatched ACKs. */     
  191.  
  192. void 
  193.   AddList(int socket)
  194. {
  195.   OutCommand* new;
  196.   
  197.   new = (OutCommand*) malloc(sizeof(OutCommand));
  198.   new->socketNum = socket;
  199.   if (listHead == NULL)
  200.     listHead = new;
  201.   if (listTail)
  202.     listTail->next = new;
  203.   listTail = new;
  204.   new->next = NULL;
  205. }
  206.  
  207.  
  208.  
  209. /* Function to remove item with socket number = 'socket' from
  210.    list of unmatched ACKs. 
  211.    Returns 0 if it is found, -1 otherwise */
  212. int 
  213.   RemoveList(int socket)
  214. {
  215.   OutCommand*    prev;
  216.   OutCommand*    current;
  217.   int        found = 0;
  218.   
  219.   prev = NULL;
  220.   current = listHead;
  221.   
  222.   while ((current) && !(found))
  223.   {
  224.     if (current->socketNum == socket)
  225.     {
  226.       if (prev)
  227.     prev->next = current->next;
  228.       else
  229.     listHead = current->next;
  230.       if (listTail == current)
  231.     listTail = prev;
  232.       free(current);
  233.       found = 1;
  234.     }
  235.     else
  236.     {
  237.       prev = current;
  238.       current = current->next;
  239.     }
  240.   }
  241.   if (found)
  242.     return 0;
  243.   else
  244.     return -1;
  245. }                                    /* end function RemoveList */
  246.  
  247.  
  248. /* Function to determine the type of reply that character c
  249.    represents. 
  250.    Returns CVDAck, Completion, CVDError, or Unknown */
  251. int 
  252.   WhichReply(char c)
  253. {
  254.   c = (c & ReplyMask);
  255.   switch (c)
  256.   {
  257.    case '\x40':
  258.     return CVDAck;
  259.    case '\x50':
  260.     return Completion;
  261.    case '\x60':
  262.     return CVDError;
  263.    default:
  264.     return CVDError;
  265.   }
  266. }                                    /* end function WhichReply */
  267.  
  268.  
  269. int CVD1000InputPending(int fd)
  270. {
  271.   fd_set        readfds;
  272.   struct timeval    waitTime;
  273.   int            result = 0;
  274.   int            descriptorTableSize = 0;
  275.   
  276.   waitTime.tv_sec = 0;                            /* Set up a zero-wait timeval to make select poll,... */
  277.   waitTime.tv_usec = 0;                            /* ...meaning that either input is ready immediately, or not */
  278.   FD_ZERO(&readfds);                            /* Initialize set of files to be checked; check no files */
  279.   FD_SET(fd, &readfds);                            /* Look for input only on the file passed in as argument */
  280.   descriptorTableSize = getdtablesize();
  281.   result = select(descriptorTableSize, &readfds, (fd_set*)NULL,
  282.           (fd_set*)NULL, &waitTime);
  283.   return(result);
  284. }                                    /* end function CVD1000InputPending */
  285.  
  286.  
  287.  
  288.  
  289. /* Sends out command in this format:
  290.    Packet = Packet header (#defined as 'Header', 
  291.    hard-coded to send to device with address 1)
  292.    + Message + Terminator (#defined as 'Terminator')
  293.    Message = Message header + Message Category + Category Mode + Specifics 
  294.    */
  295.  
  296. int CVD1000SendCode(VideoObject*    theObject,
  297.             char        msgFormat,
  298.             char        categoryCode,
  299.             char*        specific,
  300.             int            cmdLength,
  301.             int            bytesExpected)
  302. {
  303.   int    numWritten;
  304.   int    counter = 0;
  305.   int    result = 0;
  306.   char    oneChar;
  307.   char    command[20];
  308.   int        numRetries = 0;
  309.   struct termio    lineAttributes;
  310.   char        oldTimeOut;
  311.   char        oldMinChars;
  312.   
  313.   while (CVD1000InputPending(theObject->DevConfig->fd) == 1)        /* Is there data to be read from the Vdeck? */
  314.   {
  315.     result = CVD1000ReadReply(theObject);                /* Yes, consume the data */
  316.   }
  317.   
  318.   bzero(command, 4 + cmdLength);                    /* Set up command */
  319.   command[0] = Header;
  320.   command[1] = msgFormat;                        /* E.g., "Command Format1", "Inquiry", "Address" */
  321.   command[2] = categoryCode;                        /* E.g., "Vcr", "Effects", "Interface" */
  322.   bcopy(specific, &command[3], cmdLength);
  323.   command[3+cmdLength] = Terminator;
  324.   
  325.   numWritten = write(theObject->DevConfig->fd, command,            /* Send command */
  326.              4 + cmdLength);
  327.   if (numWritten == (4 + cmdLength))                    /* Was command packet correctly sent to the Vdeck? */
  328.   {                                    /* Yes, report diagnostics */
  329.     sprintf(diagMsg, "%s :\tIn CVDSendCode, wrote %d bytes:\t::",
  330.         theObject->DevConfig->serialPort,
  331.         numWritten);
  332.     PrintDiagnostics(diagMsg);
  333.     for (counter = 0; counter < 4 + cmdLength; counter++)
  334.     {
  335.       oneChar = command[counter];
  336.       sprintf(diagMsg, "%02X::", oneChar);
  337.       PrintDiagnostics(diagMsg);
  338.     }
  339.     PrintDiagnostics("\n");
  340.   }
  341.   else                                    /* No, an error occurred in sending the command to the Vdeck */
  342.   {
  343.     sprintf(diagMsg, "%s :\tWrite error.\n",
  344.         theObject->DevConfig->serialPort);
  345.     PrintDiagnostics(diagMsg);
  346.     return -1;
  347.   }
  348.   
  349.   if (msgFormat == Inq)                            /* Was the command an Inquiry? */
  350.   {
  351.     result = CVD1000ReadInquiryReply(theObject, bytesExpected);
  352.   }
  353.   else
  354.   {
  355.     result = CVD1000ReadReply(theObject);
  356.   }
  357.   return(result);
  358. }                                    /* end function CVD1000SendCode */
  359.  
  360.  
  361.  
  362. int CVD1000ReadInquiryReply(VideoObject*    theObject,
  363.                 int            bytesExpected)
  364. {
  365.   int        errorCat;
  366.   int        errorNum;
  367.   int        result = 0;
  368.   int        socket = 0;
  369.   int        counter = 0;
  370.   int        errorCount = 0;
  371.   char        oneChar;
  372.   char        theReply[20];
  373.   
  374.   sprintf(diagMsg, "%s :\t-----Entering CVD1000ReadInquiryReply.\n",
  375.       theObject->DevConfig->serialPort);
  376.   PrintDiagnostics(diagMsg);
  377.   result = read(theObject->DevConfig->fd, theReply, 1);            /* Read the 1st byte of Vdeck's reply */
  378.   if (result < 1)                            /* Did the read fail? */
  379.     return(PlayerReturnError);                        /* Yes, return an error code */
  380.   if (theReply[0] != RcvHeader)                        /* Was the expected Vdeck header character received? */
  381.   {                                    /* No, an error occurred */
  382.     sprintf(diagMsg, "%s :\tUnexpected reply from CVD1000: ::%2X::.\n",
  383.         theObject->DevConfig->serialPort, theReply[0]);
  384.     PrintDiagnostics(diagMsg);
  385.     while (theReply[0] != Terminator)                    /* Consume any leftover characters (read until Terminator... */
  386.     {                                    /* ...character is encountered) */
  387.       result = read(theObject->DevConfig->fd, theReply, 1);        /* Read another byte from the Vdeck */
  388.       if (result < 1)                            /* Did a read error occur? */
  389.     break;                                /* Yes, get out of this while loop */
  390.     }
  391.     return(PlayerReturnError);
  392.   }
  393.   result = read(theObject->DevConfig->fd, theReply, 1);            /* Read the 2nd byte of Vdeck's reply */
  394.   if (result < 1)                            /* Did the read fail? */
  395.     return(PlayerReturnError);                        /* Yes, return an error code */
  396.   socket = (theReply[0] & SocketMask);                    /* Determine the socket number for this reply */
  397.   sprintf(diagMsg, "%s :\tSecond byte of reply = %2X, socket is %d.\n",
  398.       theObject->DevConfig->serialPort,
  399.       (int)theReply[0], socket);
  400.   PrintDiagnostics(diagMsg);
  401.   RemoveList(socket);                            /* Remove socket from list */
  402.   if (WhichReply(theReply[0]) == CVDError)                /* Was an error condition returned? */
  403.   {                                    /* Yes */
  404.     RemoveList(socket);                            /* Remove socket from list */
  405.     result = read(theObject->DevConfig->fd, theReply, 1);        /* Read the error code byte from the Vdeck */
  406.     if (result < 1)                            /* Did the read fail? */
  407.       return(PlayerReturnError);                    /* Yes, return an error code */
  408.     CVD1000PrintErrorMessage((theReply[0] & ErrorCatMask),        /* Decode and print the error message */
  409.                  theReply[0] & ErrorNumMask);
  410.     result = read(theObject->DevConfig->fd, theReply, 1);        /* Read the terminator byte from the Vdeck */
  411.     return(PlayerReturnError);
  412.   }
  413.   else if (WhichReply(theReply[0] == Completion))            /* No, a Completion was read */
  414.   {
  415.     RemoveList(socket);                            /* Remove socket from list */
  416.     for (counter = 0; counter < bytesExpected; counter++)
  417.     {
  418.       result = read(theObject->DevConfig->fd, &(reply[counter]), 1); /* Read the inquiry reply information from the Vdeck */
  419.       if (result < 1)                            /* Did something go wrong with the read? */
  420.       {                                    /* Yes, print an error message and return an error code */
  421.     sprintf(diagMsg, "%s :\tError in reading inquiry reply data.  Bytes expected: %d, bytes received: %d\n.",
  422.         theObject->DevConfig->serialPort, bytesExpected,
  423.         counter);
  424.     PrintDiagnostics(diagMsg);
  425.     for (errorCount = 0; errorCount < counter; errorCount++)    /* Print bytes received so far */
  426.     {
  427.       oneChar = reply[errorCount];
  428.       sprintf(diagMsg, "%02X::", oneChar);
  429.       PrintDiagnostics(diagMsg);
  430.     }
  431.     PrintDiagnostics("\n");
  432.     return(PlayerReturnError);
  433.       }
  434.     }
  435.     sprintf(diagMsg, "%s :\tReply from Inquiry is:\t::",
  436.         theObject->DevConfig->serialPort);
  437.     PrintDiagnostics(diagMsg);
  438.     for (counter = 0; counter < bytesExpected; counter++)
  439.     {
  440.       oneChar = reply[counter];
  441.       sprintf(diagMsg, "%02X::", oneChar);
  442.       PrintDiagnostics(diagMsg);
  443.     }
  444.     PrintDiagnostics("\n");
  445.     if (reply[bytesExpected - 1] == Terminator)                /* Sometimes the Vdeck drops a byte in its response; did... */
  446.     {                                    /* ...this happen? (i.e., did an error occur?) */
  447.       return(PlayerReturnError);                    /* Yes, don't bother trying to read the message Terminator */
  448.     }
  449.     else                                /* No, the inquiry went okay; read the message Terminator */
  450.     {
  451.       result = read(theObject->DevConfig->fd, theReply, 1);        /* Read the terminator byte from the Vdeck */
  452.       if (result < 1)                            /* Did the read fail? */
  453.     return(PlayerReturnError);                    /* Yes, return an error code */
  454.       else
  455.     return(PlayerOk);
  456.     }
  457.   }                                    /* end else if (WhichReply... */
  458. }                                    /* end function CVD1000ReadInquiryReply */
  459.  
  460.  
  461.  
  462.  
  463. /* Reads response from Vdeck, checking if it is an ACK, COMPLETION, or ERROR message. */
  464. int 
  465.   CVD1000ReadReply(VideoObject* theObject)
  466. {
  467.   int        errorCat;
  468.   int        errorNum;
  469.   int        result = 0;
  470.   int        socket = 0;
  471.   char        theReply[20];
  472.   
  473.   sprintf(diagMsg, "%s :\t-----Entering CVD1000ReadReply.\n",
  474.       theObject->DevConfig->serialPort);
  475.   PrintDiagnostics(diagMsg);
  476.   
  477.   result = read(theObject->DevConfig->fd, &(theReply[0]), 1);        /* Read the 1st byte of Vdeck's reply */
  478.   if (theReply[0] != RcvHeader)                        /* Was the expected Vdeck header character received? */
  479.   {                                    /* No, an error occurred */
  480.     sprintf(diagMsg, "%s :\tUnexpected reply from CVD1000: ::%2X::.\n",
  481.         theObject->DevConfig->serialPort, theReply[0]);
  482.     PrintDiagnostics(diagMsg);
  483.     while (theReply[0] != Terminator)                    /* Consume any leftover characters (read until Terminator... */
  484.     {                                    /* ...character is encountered) */
  485.       sprintf(diagMsg, "%s :\tTrying to consume another byte.\n",
  486.           theObject->DevConfig->serialPort);
  487.       PrintDiagnostics(diagMsg);
  488.       result = read(theObject->DevConfig->fd, theReply, 1);        /* Read another byte from the Vdeck */
  489.       if (result < 1)                            /* Did a read error occur? */
  490.     break;                                /* Yes, get out of this while loop */
  491.     }
  492.     return(PlayerReturnError);
  493.   }
  494.   result = read(theObject->DevConfig->fd, &(theReply[1]), 1);        /* Read the 2nd byte of Vdeck's reply */
  495.   socket = (theReply[1] & SocketMask);                    /* Determine the socket number for this reply */
  496.   sprintf(diagMsg, "%s :\tSecond byte of reply = %2X, socket is %d.\n",
  497.       theObject->DevConfig->serialPort,
  498.       (int)theReply[1], socket);
  499.   PrintDiagnostics(diagMsg);
  500.   RemoveList(socket);                            /* Remove socket from list */
  501.   if (WhichReply(theReply[1]) == CVDError)                /* Was an error condition returned? */
  502.   {                                    /* Yes */
  503.     RemoveList(socket);                            /* Remove socket from list */
  504.     result = read(theObject->DevConfig->fd, theReply, 1);        /* Read the error code byte from the Vdeck */
  505.     CVD1000PrintErrorMessage((theReply[0] & ErrorCatMask),        /* Decode and print the error message */
  506.                  theReply[0] & ErrorNumMask);
  507.     result = read(theObject->DevConfig->fd, theReply, 1);        /* Read the terminator byte from the Vdeck */
  508.     return(PlayerReturnError);
  509.   }
  510.   else if (WhichReply(theReply[1] == CVDAck))                /* No, an ACK was read */
  511.   {
  512.     AddList(socket);                            /* Remove socket from list */
  513.     result = read(theObject->DevConfig->fd, &(theReply[2]), 1);        /* Read the terminator byte from the Vdeck */
  514.   }
  515.   else if (WhichReply(theReply[1] == Completion))            /* A Completion was read */
  516.   {
  517.     RemoveList(socket);                            /* Remove socket from list */
  518.     result = read(theObject->DevConfig->fd, &(theReply[2]), 1);        /* Read the terminator byte from the Vdeck */
  519.   }
  520.   return(PlayerOk);
  521. }                                    /* end function CVD1000ReadReply */
  522.  
  523.  
  524.  
  525. /* Asynchronous read function for reading COMPLETIONs of PlayFromTo */
  526. int
  527.   CVD1000ReadAsynch(int    fd)
  528. {
  529.   int result = 0;
  530.   
  531.   result = CVD1000ReadReply(tempObjectPtr);
  532.   SetAsynchReadFunction(NULL, fd, FeatureOff);                /* Set automatic read off */
  533. }                                    /* end function CVD1000ReadAsynch */
  534.  
  535.  
  536. /* Converts decimal to char in BCD */
  537. void 
  538.   CVD1000ConvertToBCD(int    num,
  539.               char*    bcd)
  540. {
  541.   char tmp1[1];
  542.   char tmp2[1];
  543.   
  544.   tmp1[0] = (num/10)<<4;
  545.   tmp2[0] = num%10;
  546.   tmp1[0] = tmp1[0] | tmp2[0];
  547.   bcopy(tmp1, bcd, 1);
  548.   
  549. }                                    /* end function CVD1000ConvertToBCD */
  550.  
  551.  
  552. /* Converts char in BCD to decimal */
  553. int 
  554.   CVD1000ConvertFromBCD(char bcd)
  555. {
  556.   int tmp1;
  557.   int tmp2;
  558.   tmp1 = (bcd & UpperMask)>>4;
  559.   tmp2 = bcd & LowerMask;
  560.   return (tmp1*10 + tmp2);
  561. }                                    /* end function CVD1000ConvertFromBCD */
  562.  
  563.  
  564. /* Converts time to address in frames */
  565. int
  566.   CVD1000ConvertTimeToFrame(int hr,
  567.                 int min,
  568.                 int sec,
  569.                 int frame)
  570. {
  571.   int address;
  572.   
  573.   address = FrameRate * (hr*3600 + min*60 + sec) + frame;
  574.   return address;
  575. }                                    /* end function CVD1000ConvertTimeToFrame */
  576.  
  577.  
  578. /* Converts address in frames to hr, min, sec, frames */
  579. void 
  580.   CVD1000ConvertFrameToTime(char*    hr,
  581.                 char*    min,
  582.                 char*    sec,
  583.                 char*    frame,
  584.                 int        address)
  585. {
  586.   int    h;
  587.   int    s;
  588.   int    m;
  589.   int    f;
  590.   int    framesPerHour;
  591.   int    framesPerMinute;
  592.   int    framesPerSecond;
  593.   
  594.   framesPerHour = 3600 * FrameRate;                    /* 3600 = seconds per hour */
  595.   framesPerMinute = 60 * FrameRate;
  596.   framesPerSecond = FrameRate;
  597.   
  598.   h = address / framesPerHour;
  599.   m = (address % framesPerHour) / framesPerMinute;
  600.   s = ((address % framesPerHour) % framesPerMinute) / framesPerSecond;
  601.   f = ((address % framesPerHour) % framesPerMinute) % framesPerSecond;
  602.   
  603.   CVD1000ConvertToBCD(h, hr);
  604.   CVD1000ConvertToBCD(m, min);
  605.   CVD1000ConvertToBCD(s, sec);
  606.   CVD1000ConvertToBCD(f, frame);
  607.   
  608. }                                    /* end function CVD1000ConvertFrameToTime */
  609.  
  610.  
  611. int 
  612.   CVD1000Play(VideoObject* theObject)
  613. {
  614.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Play.\n",
  615.       theObject->DevConfig->serialPort);
  616.   PrintDiagnostics(diagMsg);
  617.   command[0] = Mode1;
  618.   command[1] = '\x28';
  619.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  620. }                                    /* end function CVD1000Play */
  621.  
  622.  
  623. int 
  624.   CVD1000SearchFrame(VideoObject*    theObject,
  625.              int        address,
  626.              int        playOn)
  627. {
  628.   char sHr[1];
  629.   char sMin[1];
  630.   char sSec[1];
  631.   char sFrame[1];
  632.   int result = 0;
  633.   
  634.   sprintf(diagMsg, "\n%s :\tCVD1000SearchFrame, address is %d.\n",
  635.       theObject->DevConfig->serialPort,
  636.       address);
  637.   PrintDiagnostics(diagMsg);
  638.   CVD1000ConvertFrameToTime(sHr, sMin, sSec, sFrame, address);
  639.   bzero(command, 6);
  640.   command[0] = Search;
  641.   command[1] = TimeCode;
  642.   bcopy(sHr, &command[2], 1);
  643.   bcopy(sMin, &command[3], 1);
  644.   bcopy(sSec, &command[4], 1);
  645.   bcopy(sFrame, &command[5], 1);
  646.   if (playOn != 0)
  647.     command[6] = '\x28';                        /* Play */
  648.   else
  649.     command[6] = '\x20';                        /* Still */
  650.   return(CVD1000SendCode(theObject, Command1, Vcr, command, 7, 0));
  651. }                                    /* end function CVD1000SearchFrame */
  652.  
  653.  
  654. int 
  655.   CVD1000SearchChapter(VideoObject*    theObject,
  656.                int        startChap,
  657.                int        playOn)
  658. {
  659.   sprintf(diagMsg, "\n%s :\tEntering CVD1000SearchChapter.\n",
  660.       theObject->DevConfig->serialPort);
  661.   PrintDiagnostics(diagMsg);
  662.   bzero(command, 6);
  663.   command[0] = Search;
  664.   command[1] = ChapterCode;
  665.   command[2] = '\x00';
  666.   command[3] = '\x00';
  667.   command[4] = startChap/10;
  668.   command[5] = startChap%10;
  669.   if (playOn)
  670.     command[6] = '\x28';                        /* Play */
  671.   else
  672.     command[6] = '\x20';                        /* Still */
  673.   
  674.   CVD1000SendCode(theObject, Command1, Vcr, command, 7, 0);
  675. }                                    /* end function CVD1000SearchChapter */
  676.  
  677.  
  678. int 
  679.   CVD1000SearchIndex(VideoObject*    theObject,
  680.              int        theIndex,
  681.              int        dir)
  682. {
  683.   sprintf(diagMsg, "\n%s :\tEntering CVD1000SearchIndex.\n",
  684.       theObject->DevConfig->serialPort);
  685.   PrintDiagnostics(diagMsg);
  686.   bzero(command, 6);
  687.   command[0] = Search;
  688.   command[1] = IndexCode;
  689.   if (dir == Forward)
  690.     command[2] = '\x00';
  691.   else
  692.     command[2] = '\x40';
  693.   command[3] = '\x00';
  694.   command[4] = theIndex / 10;
  695.   command[5] = theIndex % 10;
  696.   command[6] = '\x20';
  697.   
  698.   CVD1000SendCode(theObject, Command1, Vcr, command, 7, 0);
  699. }                                    /* end function CVD1000SearchIndex */
  700.  
  701.  
  702.  
  703. /* Queries Vdeck to determine the type of counter being used (i.e., TimeCode or Chapter */
  704. int 
  705.   CVD1000QueryMedium(VideoObject*    theObject,
  706.              char*        result)
  707. {
  708.   int    chapter = 0;
  709.   
  710.   sprintf(diagMsg, "\n%s :\tEntering CVD1000QueryMedium.\n",
  711.       theObject->DevConfig->serialPort);
  712.   PrintDiagnostics(diagMsg);
  713.   command[0] = '\x52';
  714.   command[1] = '\x02';
  715.   command[2] = '\x01';
  716.   CVD1000SendCode(theObject, Inq, Vcr, command, 3, 1);
  717.   
  718.   if (((int) reply[0]) == '\x12')
  719.     chapter = PlayerChapterMode;
  720.   else
  721.     chapter = PlayerFrameMode;
  722.   return chapter;
  723. }                                    /* end function CVD1000QueryMedium */
  724.  
  725.  
  726. int 
  727.   CVD1000PlayFromTo(VideoObject*    theObject,
  728.             int            startAddress,            /* Is 0 if play from current position */
  729.             int            endAddress,            /* Denotes direction if index search */
  730.             int            speedInFramesPerSecond)
  731. {
  732.   int    chapterCode;                            /* 1 when prerecorded chapter marks exist, 0 otherwise */
  733.   int    result = 0;
  734.   char    eHr[1];
  735.   char    eMin[1];
  736.   char    eSec[1];
  737.   char    eFrame[1];
  738.   
  739.   sprintf(diagMsg, "\n%s :\tCVD1000PlayFromTo: from %d to %d.\n",
  740.       theObject->DevConfig->serialPort,
  741.       startAddress, endAddress);
  742.   PrintDiagnostics(diagMsg);
  743.   
  744.   if (addMode == PlayerChapterMode)
  745.   {
  746.     chapterCode = CVD1000QueryMedium(theObject, NULL);
  747.     sprintf(diagMsg, "%s :\tChapter code = %d.\n",
  748.         theObject->DevConfig->serialPort,
  749.         chapterCode);
  750.     PrintDiagnostics(diagMsg);
  751.     
  752.     if (chapterCode == PlayerChapterMode)
  753.     {
  754.       if (startAddress == endAddress)                    /* Simple search and still */
  755.     return(CVD1000SearchChapter(theObject, startAddress, 0));
  756.       else if (startAddress != NULL)                    /* Play from specific chapter */
  757.       {
  758.     if (CVD1000SearchChapter(theObject, startAddress, 0) == -1)
  759.     {
  760.       sprintf(diagMsg, "%s :\tStart Chapter cannot be found.\n",
  761.           theObject->DevConfig->serialPort);
  762.       PrintDiagnostics(diagMsg);
  763.       return PlayerReturnError;
  764.     }
  765.     else
  766.       CVD1000PlayAtSpeedDir(theObject, speedInFramesPerSecond, Forward);
  767.       }
  768.       else 
  769.     CVD1000PlayAtSpeedDir(theObject, speedInFramesPerSecond, Forward);  /* Play from current position */
  770.       
  771.       if (endAddress != NULL)                        /* Play till specific chapter */
  772.       {
  773.     bzero(command, 6);
  774.     command[0] = ChapterCode;
  775.     command[1] = '\x00';                        
  776.     command[2] = '\x00';
  777.     command[3] = (endAddress/10);                    /* 0X */
  778.     command[4] = (endAddress%10);                    /* OY, where XY = Chapter no. */
  779.     command[5] = '\x01';                        /* stop */
  780.     command[6] = '\x00';
  781.     CVD1000SendCode(theObject, Command3, Vcr, command, 7, 0);
  782.     tempObjectPtr = theObject;                    /* Set global variable "tempObjectPointer" to point to... */
  783.     SetAsynchReadFunction(CVD1000ReadAsynch,            /* ...current videoObject so async. read function can... */
  784.                   theObject->DevConfig->fd, FeatureOn); /* ...use the info in it. */
  785.       }
  786.       else
  787.     return PlayerOk;
  788.     }                                    /* end if (chapterCode == PlayerChapterMode */
  789.     else
  790.       return(CVD1000SearchIndex(theObject, startAddress, 
  791.                 endAddress));                /* No chapter marks, do index search instead */
  792.   }                                    /* end if (addMode == PlayerChapterMode */
  793.   if (startAddress == endAddress)                    /* Case a: search to frame "startAddress" & still */
  794.   {                                    /* (non-blocking search) */
  795.     return(CVD1000SearchFrame(theObject, startAddress, 0));
  796.   }
  797.   
  798.   if ((startAddress > 0) && (endAddress == 0))                /* Case b: search to frame "startAddress" & still */
  799.   {                                    /* (block on completion of the search) */
  800.     if (CVD1000SearchFrame(theObject, startAddress, 0) == PlayerReturnError)
  801.     {
  802.       sprintf(diagMsg, "%s :\tCVD1000PlayFromTo: Start address cannot be found.\n",
  803.           theObject->DevConfig->serialPort);
  804.       PrintDiagnostics(diagMsg);
  805.       return(PlayerReturnError);
  806.     }
  807.     else
  808.     {
  809.       sprintf(diagMsg, "%s :\tCVD1000PlayFromTo: Waiting for search to complete.\n",
  810.           theObject->DevConfig->serialPort);
  811.       PrintDiagnostics(diagMsg);
  812.       result = CVD1000WaitForCompletion(theObject);            /* Block until search is completed */
  813.       return(result);
  814.     }
  815.   }                                    /* end Case b */
  816.   
  817.   if ((startAddress == 0) && (endAddress != 0))                /* Case c: play from current position (no search) until... */
  818.   {                                    /* ...endAddress is reached, at speedInFramesPerSecond */
  819.     while (CVD1000SearchIsInProgress(theObject) != 0)            /* Is a search currently in progress? */
  820.     {                                    /* Yes, wait until it has completed before going any further */
  821.       result = CVD1000WaitForCompletion(theObject);            /* Maybe this Completion is for the current search, but... */
  822.     }                                    /* ...maybe not; that's what the while loop is for */
  823.     CVD1000PlayAtSpeedDir(theObject, speedInFramesPerSecond, Forward);
  824.     result = CVD1000WaitForCompletion(theObject);            /* Block until playback has begun */ 
  825.     CVD1000ConvertFrameToTime((char*)&eHr, (char*)&eMin,
  826.                   (char*)&eSec, (char*)&eFrame,
  827.                   endAddress);
  828.     bzero(command, 6);
  829.     command[0] = TimeCode;
  830.     bcopy(eHr, &command[1], 1);
  831.     bcopy(eMin, &command[2], 1);
  832.     bcopy(eSec, &command[3], 1);
  833.     bcopy(eFrame, &command[4], 1);
  834.     command[5] = '\x01';                        /* Still */
  835.     command[6] = '\x20';
  836.     CVD1000SendCode(theObject, Command3, Vcr, command, 7, 0);        /* Play until endAddress is reached */
  837.     tempObjectPtr = theObject;                        /* Set global variable "tempObjectPointer" to point to... */
  838.     SetAsynchReadFunction(CVD1000ReadAsynch,                /* ...current videoObject so async. read function can... */
  839.               theObject->DevConfig->fd, FeatureOn);        /* ...use the info in it. */
  840.     return(PlayerOk);
  841.   }                                    /* end Case c */
  842.   if ((startAddress != 0) && (endAddress != 0)                /* Case d: play from startAddress to endAddress in... */
  843.       && (startAddress < endAddress))                    /* ...speedInFramesPerSecond */
  844.   {
  845.     result = CVD1000QueryFrame(theObject);                /* Determine where the tape is currently positioned */
  846.     if (result != startAddress)                        /* If the tape is not where it should be, put it there */
  847.     {
  848.       CVD1000SearchFrame(theObject, startAddress, 0);            /* Search to start frame */
  849.       result = CVD1000WaitForCompletion(theObject);            /* Block until search is completed */
  850.     }
  851.     CVD1000PlayAtSpeedDir(theObject, speedInFramesPerSecond, Forward);
  852.     result = CVD1000WaitForCompletion(theObject);            /* Block until playback has begun */
  853.     CVD1000ConvertFrameToTime((char*)&eHr, (char*)&eMin,
  854.                   (char*)&eSec, (char*)&eFrame,
  855.                   endAddress);
  856.     bzero(command, 6);
  857.     command[0] = TimeCode;
  858.     bcopy(eHr, &command[1], 1);
  859.     bcopy(eMin, &command[2], 1);
  860.     bcopy(eSec, &command[3], 1);
  861.     bcopy(eFrame, &command[4], 1);
  862.     command[5] = '\x01';                        /* Still */
  863.     command[6] = '\x20';
  864.     CVD1000SendCode(theObject, Command3, Vcr, command, 7, 0);        /* Play until endAddress is reached */
  865.     return(PlayerOk);
  866.   }                                    /* end Case d */
  867.   else
  868.     return(PlayerReturnError);
  869. }                                    /* end function CVD1000PlayFromTo */
  870.  
  871.  
  872.  
  873. int 
  874.   CVD1000Record(VideoObject* theObject)
  875. {
  876.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Record.\n",
  877.       theObject->DevConfig->serialPort);
  878.   PrintDiagnostics(diagMsg);
  879.   command[0] = Mode1;
  880.   command[1] = '\x48';
  881.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  882. }                                    /* end function CVD1000Record */
  883.  
  884.  
  885.  
  886.  
  887. int 
  888.   CVD1000RecordFromTo(VideoObject*    theObject,
  889.             int            startAddress,
  890.             int            endAddress,
  891.             int            speedInFramesPerSecond)
  892. {
  893.   int    result = 0;
  894.   int    hour, minute, second, frame, tick;
  895.   int    ticksPerSecond, ticksPerFrame;
  896.   int    offsetAddress;
  897.   char    eHr[1];
  898.   char    eMin[1];
  899.   char    eSec[1];
  900.   char    eFrame[1];
  901.   char    eTick1[1];
  902.   char    eTick2[2];
  903.   
  904.   sprintf(diagMsg, "\n%s :\tEntering CVD1000RecordFromTo.\n",
  905.       theObject->DevConfig->serialPort);
  906.   PrintDiagnostics(diagMsg);
  907.   sprintf(diagMsg, "%s :\tRecord from %d to %d.\n",
  908.       theObject->DevConfig->serialPort,
  909.       startAddress, endAddress);
  910.   PrintDiagnostics(diagMsg);
  911.   
  912.   if (addMode == PlayerChapterMode)                    /* Cannot insert edit in chapter mode, only in frame mode */
  913.   {
  914.     sprintf(diagMsg, "%s :\tMust be in frame addressing mode to do insert editing.\n",
  915.         theObject->DevConfig->serialPort);
  916.     PrintDiagnostics(diagMsg);
  917.     DisplayError("Cannot perform insert editing in chapter mode.","Please make sure deck addressing is in frame address mode.");
  918.     return(PlayerReturnError);
  919.   }                                    /* end if (addMode == PlayerChapterMode */
  920.   
  921.   while (CVD1000SearchIsInProgress(theObject) != 0)            /* Is a search currently in progress? */
  922.   {                                    /* Yes, wait until it has completed before going any further */
  923.     sprintf(diagMsg, "\n%s :\tCVD1000RecordFromTo: Search still in progress, waiting.\n",
  924.         theObject->DevConfig->serialPort);
  925.     PrintDiagnostics(diagMsg);
  926.     result = CVD1000WaitForCompletion(theObject);            /* Maybe this Completion is for the current search, but... */
  927.   }                                    /* ...maybe not; that's what the while loop is for */
  928.   
  929.   if ((startAddress == 0) && (endAddress == 0))                /* Put player into insert edit mode and return successfully */
  930.   {
  931.     command[0] = EditCtrl;
  932.     command[1] = '\x40';                        /* Edit Rec Standby */
  933.     CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  934.     result = CVD1000WaitForCompletion(theObject);            /* Block until Edit Rec Standby command has completed */
  935.     return(PlayerOk);
  936.   }
  937.   if ((startAddress == 0) && (endAddress > 0))                /* Perform insert editing, until 'endAddress' is reached */
  938.   {
  939.     command[0] = '\x03';                        /* Inquire about the current VISCA clock reading */
  940.     CVD1000SendCode(theObject, Inq, Interface, command, 1, 7);
  941.     bzero(command, 6);                            /* Format the command data */
  942.     command[0] = reply[0];                        /* Copy current VISCA time into new command data */
  943.     command[1] = reply[1];
  944.     command[2] = reply[2];
  945.     command[3] = reply[3];
  946.     command[4] = reply[4];
  947.     command[5] = '\x05';                        /* Edit Record */
  948.     command[6] = '\x48';
  949.     CVD1000SendCode(theObject, Command2, Vcr, command, 7, 0);        /* Begin edit recording right now, at current VISCA clock */
  950.     result = CVD1000WaitForCompletion(theObject);            /* Block until Edit Record command has begun executing */
  951.     
  952.     CVD1000ConvertFrameToTime((char*)&eHr, (char*)&eMin,        /* Format the ending time for the Vdeck's record operation */
  953.                   (char*)&eSec, (char*)&eFrame,
  954.                   endAddress);
  955.     bzero(command, 6);                            /* Tell the Vdeck to record until the following... */
  956.     command[0] = TimeCode;                        /* ...timecode is reached */
  957.     bcopy(eHr, &command[1], 1);
  958.     bcopy(eMin, &command[2], 1);
  959.     bcopy(eSec, &command[3], 1);
  960.     bcopy(eFrame, &command[4], 1);
  961.     command[5] = '\x05';                        /* Go into Edit Rec Standby when recording is done */
  962.     command[6] = '\x40';
  963.     result = CVD1000SendCode(theObject, Command3, Vcr, command, 7, 0); /* Record until endAddress is reached */
  964.     result = CVD1000WaitForCompletion(theObject);            /* Block until Edit Rec Standby command has completed */
  965.     return(result);
  966.   }
  967. }                                    /* end function CVD1000RecordFromTo */
  968.  
  969.  
  970.  
  971. int 
  972.   CVD1000FastForward(VideoObject* theObject)
  973. {
  974.   int    status = 0;
  975.   
  976.   sprintf(diagMsg, "\n%s :\tEntering CVD1000FastForward.\n",
  977.       theObject->DevConfig->serialPort);
  978.   PrintDiagnostics(diagMsg);
  979.   status = CVD1000QueryStatus(theObject);                /* Check if in play mode */
  980.   
  981.   if (status != PlayerReturnError)
  982.     switch (status)
  983.     {
  984.      case PlayerStop:
  985.      case CVD1000StopTapeTop:
  986.      case CVD1000StopTapeEnd:
  987.      case CVD1000StopEmergency:
  988.       command[1] = '\x08';                        /* Scan */
  989.       break;
  990.      default:
  991.       command[1] = '\x2E';                        /* Fast forward */
  992.     }
  993.   else
  994.   {
  995.     sprintf(diagMsg, "%s :\tResponse for fast forward is wrong.\n",
  996.         theObject->DevConfig->serialPort);
  997.     PrintDiagnostics(diagMsg);
  998.     return PlayerReturnError;
  999.   }
  1000.   command[0] = Mode1;
  1001.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1002. }                                    /* end function CVD1000FastForward */
  1003.  
  1004.  
  1005.  
  1006. int 
  1007.   CVD1000Reverse(VideoObject* theObject)
  1008. {
  1009.   int    status = 0;
  1010.   
  1011.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Reverse.\n",
  1012.       theObject->DevConfig->serialPort);
  1013.   PrintDiagnostics(diagMsg);
  1014.   status = CVD1000QueryStatus(theObject);                /* Check if in play mode */
  1015.   
  1016.   if (status != PlayerReturnError)
  1017.     switch (status)
  1018.     {
  1019.      case PlayerStop:
  1020.      case CVD1000StopTapeTop:
  1021.      case CVD1000StopTapeEnd:
  1022.      case CVD1000StopEmergency:
  1023.       command[1] = '\x10';                        /* Reverse Scan */
  1024.       break;
  1025.      default:
  1026.       command[1] = '\x3E';                        /* Reverse */
  1027.     }
  1028.   else
  1029.   {
  1030.     sprintf(diagMsg, "%s :\tResponse for reverse is wrong.\n",
  1031.         theObject->DevConfig->serialPort);
  1032.     return PlayerReturnError;
  1033.   }
  1034.   command[0] = Mode1;
  1035.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1036. }                                    /* end function CVD1000Reverse */
  1037.  
  1038.  
  1039.  
  1040. /* This function will determine the closest matching speed for
  1041.  * the CVD1000 player, given a desired frame rate.
  1042.  * This function returns speeds in terms of NTSC frame rates
  1043.  * (30 frames per second), although the calculations are done
  1044.  * independent of frame rate.  The return values are not generic
  1045.  * because the calling function (namely, CVD1000PlayAtSpeedDir)
  1046.  * switches on the return value, and the "switch" statement in C
  1047.  * can only use constant expressions in the "case" part of the
  1048.  * statement (i.e., there can be no "case FrameRate * 2", only
  1049.  * "case 60").  So, we arbitrarily chose NTSC frame rates as our
  1050.  * standard return values.  This should not hurt the generality of the
  1051.  * rest of the driver in terms of frame rates.
  1052.  */
  1053.  
  1054. int 
  1055.   CVD1000CalcSpeed(VideoObject*    theObject,
  1056.            int        inputValue,
  1057.            int        playMode)                /* Don't care */
  1058. {
  1059.   if (inputValue < ((FrameRate / 10) + 1))                /* Less than about 0.1 * FrameRate? */
  1060.     return 3;
  1061.   else if (inputValue < (FrameRate / 2))                /* Less than 0.5 * FrameRate? */
  1062.     return 6;
  1063.   else if (inputValue < (FrameRate + (FrameRate / 2)))            /* Less than 1.5 * FrameRate? */
  1064.     return 30;
  1065.   else 
  1066.     return 60;
  1067. }                                    /* end function CVD1000CalcSpeed */
  1068.  
  1069.  
  1070. int 
  1071.   CVD1000PlayAtSpeedDir(VideoObject*    theObject,
  1072.             int        speedInFramesPerSecond,
  1073.             enum Direction    direction)
  1074. {
  1075.   int        convertedSpeed;
  1076.   static int    lastSpeed = 0;
  1077.   
  1078.   convertedSpeed = CVD1000CalcSpeed(theObject, speedInFramesPerSecond, 0);
  1079.   
  1080.   lastSpeed = convertedSpeed;
  1081.   sprintf(diagMsg, "\n%s :\tEntering CVD1000PlayAtSpeedDir.\n",
  1082.       theObject->DevConfig->serialPort);
  1083.   PrintDiagnostics(diagMsg);
  1084.   if (direction == Forward)
  1085.     switch (convertedSpeed)
  1086.     {
  1087.      case 3:                                /* 1/10th speed */
  1088.       command[1] = '\x24';
  1089.       break;
  1090.      case 6:                                /* 1/5th speed */
  1091.       command[1] = '\x26';
  1092.       break;
  1093.      case 30:                                /* 1x speed */
  1094.       command[1] = '\x28';
  1095.       break;
  1096.      case 60:                                /* 2x speed */
  1097.       command[1] = '\x2A';
  1098.       break;
  1099.      default:
  1100.       sprintf(diagMsg, "%s :\tConverted speed is wrong.\n",
  1101.           theObject->DevConfig->serialPort);
  1102.       PrintDiagnostics(diagMsg);
  1103.     }
  1104.   else
  1105.     switch (convertedSpeed)
  1106.     {
  1107.      case 3:                                /* 1/10th speed reverse */
  1108.       command[1] = '\x34';
  1109.       break;
  1110.      case 6:                                /* 1/5th speed reverse */
  1111.       command[1] = '\x36';
  1112.       break;
  1113.      case 30:                                /* 1x speed reverse */
  1114.       command[1] = '\x38';
  1115.       break;
  1116.      case 60:                                /* 2x speed reverse */
  1117.       command[1] = '\x3A';
  1118.       break;
  1119.      default:
  1120.       sprintf(diagMsg, "%s :\tConverted speed is wrong.\n",
  1121.           theObject->DevConfig->serialPort);
  1122.       PrintDiagnostics(diagMsg);
  1123.     }
  1124.   command[0] = Mode1;
  1125.   return(CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0));
  1126. }                                    /* end function CVD1000PlayAtSpeedDir */
  1127.  
  1128.  
  1129. int 
  1130.   CVD1000Still(VideoObject* theObject)
  1131. {
  1132.   int status = 0;
  1133.   
  1134.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Still.\n",
  1135.       theObject->DevConfig->serialPort);
  1136.   PrintDiagnostics(diagMsg);
  1137.   status = CVD1000QueryStatus(theObject);                /* Check if in play mode */
  1138.   
  1139.   command[0] = Mode1;
  1140.   if (status != PlayerReturnError)
  1141.     switch (status)
  1142.     {
  1143.      case PlayerStill:
  1144.       command[1] = '\x28';                        /* Play */
  1145.       break;
  1146.      case PlayerForwardPlay:
  1147.      case PlayerReversePlay:
  1148.      case PlayerForwardFast:
  1149.      case PlayerReverseFast:
  1150.      case CVD1000ForwardSlow2:
  1151.      case CVD1000ForwardSlow1:
  1152.      case CVD1000ForwardFast1:
  1153.      case CVD1000ReverseSlow2:
  1154.      case CVD1000ReverseSlow1:
  1155.      case CVD1000ReverseFast1:
  1156.       command[1] = '\x20';                        /* Still */
  1157.       break;
  1158.      default:
  1159.       return PlayerOk;                            /* Don't do anything */
  1160.     }
  1161.   else
  1162.   {
  1163.     sprintf(diagMsg, "%s :\tResponse for query status is wrong.\n",
  1164.         theObject->DevConfig->serialPort);
  1165.     return PlayerReturnError;
  1166.   }
  1167.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1168. }                                    /* end function CVD1000Still */
  1169.  
  1170.  
  1171.  
  1172. int 
  1173.   CVD1000Step(VideoObject*    theObject,
  1174.           enum Direction    direction)
  1175. {
  1176.   int    result = 0;
  1177.   
  1178.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Step.\n",
  1179.       theObject->DevConfig->serialPort);
  1180.   PrintDiagnostics(diagMsg);
  1181.   command[0] = Mode1;                            /* Still the playback first */
  1182.   command[1] = '\x20';
  1183.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1184.   result = CVD1000WaitForCompletion(theObject);                /* Block until Still command has completed */
  1185.   command[0] = Mode2;
  1186.   if (direction == Forward)
  1187.     command[1] = '\x02';
  1188.   else
  1189.     command[1] = '\x03';
  1190.   
  1191.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1192. }                                    /* end function CVD1000Step */
  1193.  
  1194.  
  1195.  
  1196. int 
  1197.   CVD1000Stop(VideoObject* theObject)
  1198. {
  1199.   OutCommand* current;
  1200.   
  1201.   SetAsynchReadFunction(NULL, theObject->DevConfig->fd, FeatureOff); /* Set automatic read off, if it is currently on */
  1202.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Stop.\n",
  1203.       theObject->DevConfig->serialPort);
  1204.   PrintDiagnostics(diagMsg);
  1205.   for (current = listHead; current; current = current->next)        /* Clear all outstanding commands */
  1206.   {
  1207.     RemoveList(current->socketNum);
  1208.   }
  1209.   command[0] = '\x01';
  1210.   CVD1000SendCode(theObject, Command1, Interface, command, 1, 0);   /* Clear the VISCA command buffer */
  1211.   command[0] = Mode1;
  1212.   command[1] = '\x00';                            /* Stop */
  1213.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1214. }                                    /* end function CVD1000Stop */
  1215.  
  1216.  
  1217.  
  1218. int 
  1219.   CVD1000SetDefaults(VideoObject*    theObject,
  1220.              int        audio,
  1221.              int        addressingMode,
  1222.              int        addressDisplayOnOff,
  1223.              int        displayMode)
  1224. {
  1225.   sprintf(diagMsg, "\n%s :\tEntering CVD1000SetDefaults.\n",
  1226.       theObject->DevConfig->serialPort);
  1227.   PrintDiagnostics(diagMsg);
  1228.   CVD1000Power(theObject, FeatureOn);
  1229.   CVD1000SetAddMode(theObject, PlayerFrameMode);
  1230.   videoDisplay = FeatureOn;
  1231.   
  1232. }                                    /* end function CVD1000SetDefaults */
  1233.  
  1234.  
  1235. int                                    /* Not implemented */
  1236.   CVD1000SetAudio(VideoObject*    theObject,
  1237.           int        mode)
  1238. {
  1239.   return;
  1240. }                                    /* end function CVD1000SetAudio */
  1241.  
  1242.  
  1243. int 
  1244.   CVD1000SetVideo(VideoObject*    theObject,
  1245.           int        mode)
  1246. {
  1247.   int result;
  1248.   
  1249.   sprintf(diagMsg, "\n%s :\tEntering CVD1000SetVideo.\n",
  1250.       theObject->DevConfig->serialPort);
  1251.   PrintDiagnostics(diagMsg);
  1252.   if (mode != videoDisplay)                        /* Only capable of toggling display, so 
  1253.                                        execute only when mode required not the same
  1254.                                        as current state */
  1255.   {
  1256.     command[0] = SubCtrl;
  1257.     command[1] = '\x45';
  1258.     CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0); 
  1259.     videoDisplay == mode;
  1260.     return result;
  1261.   }
  1262. }                                    /* end function CVD1000SetVideo */
  1263.  
  1264.  
  1265.  
  1266. int 
  1267.   CVD1000SetAddMode(VideoObject*    theObject,
  1268.             int            mode)
  1269. {
  1270.   addMode = mode;
  1271. }                                    /* end function CVD1000SetAddMode */
  1272.  
  1273.  
  1274.  
  1275. int 
  1276.   CVD1000SetAddressDisplay(VideoObject*    theObject,
  1277.                int        onOff,
  1278.                int        mode)
  1279. {
  1280.   sprintf(diagMsg, "\n%s :\tEntering CVD1000SetAddressDisplay.\n",
  1281.       theObject->DevConfig->serialPort);
  1282.   PrintDiagnostics(diagMsg);
  1283.   command[0] = OSD;
  1284.   if (onOff == FeatureOff)
  1285.     command[1] = '\x00';
  1286.   else
  1287.     command[1] = '\x05';                        /* Time code with chapter */
  1288.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1289. }                                    /* end function CVD1000SetAddressDisplay */
  1290.  
  1291.  
  1292.  
  1293. int 
  1294.   CVD1000Eject(VideoObject* theObject)
  1295. {
  1296.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Eject.\n",
  1297.       theObject->DevConfig->serialPort);
  1298.   PrintDiagnostics(diagMsg);
  1299.   command[0] = Mode1;
  1300.   command[1] = '\x18';
  1301.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1302. }                                    /* end function CVD1000Eject */
  1303.  
  1304.  
  1305.  
  1306. int 
  1307.   CVD1000Power(VideoObject*    theObject,
  1308.            int        mode)
  1309. {
  1310.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Power.\n",
  1311.       theObject->DevConfig->serialPort);
  1312.   PrintDiagnostics(diagMsg);
  1313.   command[0] = '\x01';
  1314.   CVD1000SendCode(theObject, Command1, Interface, command, 1, 0);   /* Clear the VISCA command buffer */
  1315.   if (mode == FeatureOn)
  1316.     command[1] = '\x02';
  1317.   else if (mode == FeatureOff)
  1318.     command[1] = '\x03';
  1319.   else 
  1320.   {
  1321.     command[0] = '\x00';                        /* Toggles : need to find current state first */
  1322.     CVD1000SendCode(theObject, Inq, Vcr, command, 1, 1);        /* Inquiry stores one-byte reply in "reply" array */
  1323.     if (((int) reply[0]) == '\x02')
  1324.       command[1] = '\x03';
  1325.     else if (((int) reply[0]) == '\x03')
  1326.       command[1] = '\x02';
  1327.     else
  1328.     {
  1329.     sprintf(diagMsg, "%s :\tResponse for Power inquiry is wrong : ::%2X::.\n",
  1330.         theObject->DevConfig->serialPort,
  1331.         (int)reply[0]);
  1332.     PrintDiagnostics(diagMsg);
  1333.     return PlayerReturnError;
  1334.       }
  1335.   }
  1336.   command[0] = CVDPower;
  1337.   CVD1000SendCode(theObject, Command1, Vcr, command, 2, 0);
  1338. }                                    /* end function CVD1000Power */
  1339.  
  1340.  
  1341.  
  1342. int 
  1343.   CVD1000QueryFrame(VideoObject* theObject)
  1344. {
  1345.   int        hr;
  1346.   int        min;
  1347.   int        sec;
  1348.   int        frame;
  1349.   int        result = PlayerOk;
  1350.   OutCommand*    current;
  1351.   
  1352.   sprintf(diagMsg, "\n%s :\tEntering CVD1000QueryFrame.\n",
  1353.       theObject->DevConfig->serialPort);
  1354.   PrintDiagnostics(diagMsg);
  1355.   command[0] = Search;
  1356.   command[1] = '\x20';
  1357.   
  1358.   result = CVD1000SendCode(theObject, Inq, Vcr, command, 2, 10);    /* Returns 10 data bytes */
  1359.   
  1360.   if (result != PlayerOk)                        /* Did the inquiry fail? */
  1361.   {                                    /* Yes, keep trying the inquiry until it succeeds */
  1362.     sprintf(diagMsg, "\n%s :\tTimecode inquiry failed.\n",
  1363.         theObject->DevConfig->serialPort);
  1364.     PrintDiagnostics(diagMsg);
  1365.     command[0] = '\x01';
  1366.     CVD1000SendCode(theObject, Command1, Interface, command, 1, 0);   /* Clear the VISCA command buffer */
  1367.     return(PlayerReturnError);
  1368.   }
  1369.   if (((int) reply[0]) != '\x21')
  1370.   {
  1371.     sprintf(diagMsg, "%s :\tResponse for frame inquiry is wrong.\n",
  1372.         theObject->DevConfig->serialPort);
  1373.     PrintDiagnostics(diagMsg);
  1374.     return(PlayerReturnError);
  1375.   }
  1376.   
  1377.   hr = CVD1000ConvertFromBCD(reply[1]);
  1378.   min = CVD1000ConvertFromBCD(reply[2]);
  1379.   sec = CVD1000ConvertFromBCD(reply[3]);
  1380.   frame = CVD1000ConvertFromBCD(reply[4]);
  1381.   return (CVD1000ConvertTimeToFrame(hr, min, sec, frame));
  1382. }                                    /* end function CVD1000QueryFrame */
  1383.  
  1384.  
  1385.  
  1386. int 
  1387.   CVD1000QueryChapter(VideoObject* theObject)
  1388. {
  1389.   int    chapter;
  1390.   
  1391.   sprintf(diagMsg, "\n%s :\tEntering CVD1000QueryChapter.\n",
  1392.       theObject->DevConfig->serialPort);
  1393.   PrintDiagnostics(diagMsg);
  1394.   if (CVD1000QueryMedium(theObject, (char*)NULL) != PlayerChapterMode)
  1395.   {
  1396.     DisplayError("There are no prerecorded chapters","on this tape");
  1397.     return PlayerReturnError;
  1398.   }
  1399.   
  1400.   command[0] = Search;
  1401.   command[1] = '\x30';
  1402.   CVD1000SendCode(theObject, Inq, Vcr, command, 2, 10);            /* Inquiry returns 10 data bytes */
  1403.   
  1404.   if (((int) reply[0]) != '\x31')
  1405.   {
  1406.     sprintf(diagMsg, "%s :\tResponse for chapter inquiry is wrong.\n",
  1407.         theObject->DevConfig->serialPort);
  1408.     PrintDiagnostics(diagMsg);
  1409.     return PlayerReturnError;
  1410.   }
  1411.   chapter = reply[3] * 10;
  1412.   chapter += reply[4];
  1413.   return chapter;
  1414. }                                    /* end function CVD1000QueryChapter */
  1415.  
  1416.  
  1417.  
  1418. int                                    /* Not implemented */
  1419.   CVD1000QueryAudio(VideoObject* theObject)
  1420. {
  1421.   return;
  1422. }                                    /* end function CVD1000QueryAudio */
  1423.  
  1424.  
  1425.  
  1426. int 
  1427.   CVD1000QueryVideo(VideoObject* theObject)
  1428. {
  1429.   return videoDisplay;
  1430. }                                    /* end function CVD1000QueryVideo */
  1431.  
  1432.  
  1433.  
  1434. int 
  1435.   CVD1000QueryStatus(VideoObject* theObject)
  1436. {
  1437.   sprintf(diagMsg, "\n%s :\tEntering CVD1000QueryStatus.\n",
  1438.       theObject->DevConfig->serialPort);
  1439.   PrintDiagnostics(diagMsg);
  1440.   command[0] = '\x01';
  1441.   CVD1000SendCode(theObject, Inq, Vcr, command, 1, 1);            /* Inquiry returns one (1) data byte */
  1442.   
  1443.   switch ((int) reply[0])
  1444.   {
  1445.    case '\x00':
  1446.     return PlayerStop;
  1447.    case '\x02':
  1448.     return CVD1000StopTapeTop;
  1449.    case '\x04':
  1450.     return CVD1000StopTapeEnd;
  1451.    case '\x06':
  1452.     return CVD1000StopEmergency;
  1453.    case '\x08':
  1454.     return PlayerForwardFast;
  1455.    case '\x10':
  1456.     return PlayerReverseFast;
  1457.    case '\x18':
  1458.     return PlayerEject;
  1459.    case '\x20':
  1460.     return PlayerStill;
  1461.    case '\x24':
  1462.     return CVD1000ForwardSlow2;
  1463.    case '\x26':
  1464.     return CVD1000ForwardSlow1;
  1465.    case '\x28':
  1466.     return PlayerForwardPlay;
  1467.    case '\x2A':
  1468.     return CVD1000ForwardFast1;
  1469.    case '\x2E':
  1470.     return PlayerForwardFast;
  1471.    case '\x34':
  1472.     return CVD1000ReverseSlow2;
  1473.    case '\x36':
  1474.     return CVD1000ReverseSlow1;
  1475.    case '\x38':
  1476.     return PlayerReversePlay;
  1477.    case '\x3A':
  1478.     return CVD1000ReverseFast1;
  1479.    case '\x3E':
  1480.     return PlayerReverseFast;
  1481.    case '\x40':
  1482.     return PlayerRecordPause;
  1483.    case '\x48':
  1484.     return PlayerRecording;
  1485.    default:
  1486.     sprintf(diagMsg, "%s :\tResponse for query status is wrong : Unrecognized status.\n",
  1487.         theObject->DevConfig->serialPort);
  1488.     PrintDiagnostics(diagMsg);
  1489.     return PlayerReturnError;
  1490.   }                                    /* end switch */
  1491. }                                    /* end function CVD1000QueryStatus */
  1492.  
  1493.  
  1494.  
  1495. int 
  1496.   CVD1000Ping(VideoObject* theObject)
  1497. {
  1498.   int nr;
  1499.   char response[3];
  1500.   char command[6];
  1501.   
  1502.   bzero(command, 6);                            /* Power on command */
  1503.   command[0] = Header;
  1504.   command[1] = '\x01';
  1505.   command[2] = '\x02';
  1506.   command[3] = '\x00';
  1507.   command[4] = '\x02';
  1508.   command[5] = Terminator;
  1509.   
  1510.   write(theObject->DevConfig->fd, command, 6);
  1511.   sprintf(diagMsg, "%s :\tSent ping...",
  1512.       theObject->DevConfig->serialPort);
  1513.   PrintDiagnostics(diagMsg);
  1514.   nr = read(theObject->DevConfig->fd, response, 3);            /* Read Ack */
  1515.   if (nr != 0)
  1516.   {
  1517.     sprintf(diagMsg, "%s :\tPing was successful.\n",
  1518.         theObject->DevConfig->serialPort);
  1519.     PrintDiagnostics(diagMsg);
  1520.     read(theObject->DevConfig->fd, response, 3);            /* Read Completion */
  1521.   }
  1522.   else
  1523.   {
  1524.     sprintf(diagMsg, "%s :\tPing failed.\n",
  1525.         theObject->DevConfig->serialPort);
  1526.     PrintDiagnostics(diagMsg);
  1527.   }
  1528.   return nr;
  1529. }                                    /* end function CVD1000Ping */
  1530.  
  1531.  
  1532. void CVD1000PrintErrorMessage(int errorCategory, int errorNumber)
  1533. {
  1534.   if (errorCategory == '\x00')
  1535.   {
  1536.     switch (errorNumber)
  1537.     {
  1538.      case '\x01':
  1539.       sprintf(diagMsg, "Error type : message length error (>14 bytes).\n");
  1540.       break;
  1541.      case '\x02':
  1542.       sprintf(diagMsg, "Error type : syntax error.\n");
  1543.       break;
  1544.      case '\x03':
  1545.       sprintf(diagMsg, "Error type : command buffer full.\n");
  1546.       break;
  1547.      case '\x04':
  1548.       sprintf(diagMsg, "Error type : command cancelled.\n");
  1549.       break;
  1550.      case '\x05':
  1551.       sprintf(diagMsg, "Error type : no such socket (to be cancelled).\n");
  1552.       break;
  1553.     }      
  1554.   }                                    /* end if (errorCategory... */
  1555.   else if (errorCategory == '\x40')
  1556.   {
  1557.     switch (errorNumber)
  1558.     {
  1559.      case '\x00':
  1560.       sprintf(diagMsg, "Error type : Power off.\n");
  1561.       DisplayError("Command cannot be executed because", "power is off");
  1562.       break;
  1563.      case '\x01':
  1564.       sprintf(diagMsg, "Error type : Command failed.\n");
  1565.       break;
  1566.      case '\x02':
  1567.       sprintf(diagMsg, "Error type : Search error.\n");
  1568.       DisplayError("Unable to search address", " ");
  1569.       break;
  1570.      case '\x03':
  1571.       sprintf(diagMsg, "Error type : Condition error.\n");
  1572.       break;
  1573.      case '\x06':
  1574.       sprintf(diagMsg, "Error type : Counter type error.\n");
  1575.       break;
  1576.      case '\x07':
  1577.       sprintf(diagMsg, "Error type : Tuner error.\n");
  1578.       DisplayError("Tuner error", " ");
  1579.       break;
  1580.      case '\x08':
  1581.       sprintf(diagMsg, "Error type : Emergency stop error.\n");
  1582.       break;
  1583.      case '\x09':
  1584.       sprintf(diagMsg, "Error type : No cassette inserted.\n");
  1585.       DisplayError("No cassette inserted", "Please insert cassette into deck");
  1586.       break;
  1587.      case '\x0A':
  1588.       sprintf(diagMsg, "Error type : Register error.\n");
  1589.       break;
  1590.      case '\x0B':
  1591.       sprintf(diagMsg, "Error type : Register mode setting error.\n");
  1592.       break;
  1593.     }                                    /* end switch (errorNumber... */
  1594.   }                                    /* end if */
  1595.   PrintDiagnostics(diagMsg);
  1596.   return;
  1597. }                                    /* end function CVD1000PrintErrorMessage */
  1598.  
  1599.  
  1600. int CVD1000Cancel(VideoObject*    theObject,
  1601.           int        socketNumber)
  1602. {
  1603.   int    numWritten;
  1604.   char    cancelCommand[20];
  1605.   
  1606.   sprintf(diagMsg, "\n%s :\tEntering CVD1000Cancel, socket number %d.\n",
  1607.       theObject->DevConfig->serialPort, socketNumber);
  1608.   PrintDiagnostics(diagMsg);
  1609.   cancelCommand[0] = '\x2F' & socketNumber;
  1610.   numWritten = write(theObject->DevConfig->fd, cancelCommand, 1);   /* Send command */
  1611.   
  1612.   if (numWritten < 1)                            /* Was there an error in sending the Cancel command? */
  1613.   {                                    /* Yes, report diagnostics */
  1614.     sprintf(diagMsg, "%s :\tError sending the Cancel command.\n",
  1615.         theObject->DevConfig->serialPort);
  1616.     PrintDiagnostics(diagMsg);
  1617.     return(PlayerReturnError);
  1618.   }
  1619.   else
  1620.   {
  1621.     sprintf(diagMsg, "%s :\tCancelled command with socket number %d.\n",
  1622.         theObject->DevConfig->serialPort,
  1623.         socketNumber);
  1624.   }
  1625.   return(CVD1000ReadReply(theObject));
  1626. }                                    /* end function CVD1000Cancel */
  1627.  
  1628.  
  1629.  
  1630. /* This function blocks until the current command has been executed. */
  1631.  
  1632. int CVD1000WaitForCompletion(VideoObject* theObject)
  1633. {
  1634.   int result = 0;
  1635.   
  1636.   while (CVD1000InputPending(theObject->DevConfig->fd) != 1)        /* Block until Completion message is received */
  1637.   {
  1638.     result = 0;
  1639.   }
  1640.   return(CVD1000ReadReply(theObject));                    /* Consume the reply for the command just completed */
  1641. }                                    /* end function CVD1000WaitForCompletion */
  1642.  
  1643.  
  1644. int CVD1000SearchIsInProgress(VideoObject* theObject)
  1645. {
  1646.   char    searchResult;
  1647.   
  1648.   sprintf(diagMsg, "\n%s :\tEntering CVD1000SearchIsInProgress.\n",
  1649.       theObject->DevConfig->serialPort);
  1650.   PrintDiagnostics(diagMsg);
  1651.   command[0] = Transport;                        /* Transport Inquiries tell if a search is in progress */
  1652.   CVD1000SendCode(theObject, Inq, Vcr, command, 1, 7);            /* Inquiry returns seven data bytes */
  1653.   searchResult = reply[1] & SearchInProgressMask;            /* Second byte of reply tells whether search is in progress */
  1654.   return(searchResult);                            /* Non-zero return value means search is in progress */
  1655. }                                    /* end function CVD1000SearchIsInProgress */
  1656.  
  1657.  
  1658. int CVD1000EditIsInProgress(VideoObject* theObject)
  1659. {
  1660.   char    editResult;
  1661.   
  1662.   command[0] = Transport;                        /* Transport Inquiries tell if an edit is in progress */
  1663.   CVD1000SendCode(theObject, Inq, Vcr, command, 1, 7);            /* Inquiry returns seven data bytes */
  1664.   editResult = reply[1] & EditInProgressMask;                /* Second byte of reply tells whether edit is in progress */
  1665.   return(editResult);                            /* Non-zero return value means edit is in progress */
  1666. }                                    /* end function CVD1000EditIsInProgress */
  1667.